#ifndef _STUN_MESSAGE_H
#define _STUN_MESSAGE_H

#include <ostream>
#include <cstdint>
#include <memory>
#include <unordered_map>

#include "stun_header.h"
#include "stun_attribute.h"

#define STUN_MAX_UNKNOWN_ATTRIBUTES 8
#define TURN_MAX_XOR_PEER_ADDR      8

typedef struct{
    uint32_t long_part_[4];
}  uint128_t;

typedef struct {
    uint32_t long_part_[3];
}  uint96_t;

struct StunAtrAddress
{
    uint8_t family_;
    uint16_t port_;
    union
    {
        uint32_t ipv4_;  // in host byte order
        uint128_t ipv6_; // in network byte order
    } addr_;
};

class StunMessage
{
public:
   StunMessage();
   StunMessage(const StunMessage& message);
   StunMessage& operator=(const StunMessage& rhs);
   StunMessage(const StunMessage&& message) = delete;
   StunMessage& operator=(const StunMessage&& rhs) = delete;
   ~StunMessage();

   uint32_t stun_encode_message(char* buffer, uint16_t length);
   bool stun_parse_message( char* buffer, uint16_t length);

    bool stun_parse_atr_xor_address( char* body, uint16_t buffer_len, StunAtrAddress& result);
    bool stun_parse_atr_address( char* body, uint16_t hdr_len, StunAtrAddress& result);
    void apply_xor_to_address(const StunAtrAddress& input, StunAtrAddress& output);

    uint16_t get_reflexive_port() const;
    std::string get_reflexive_address() const;

private:
    StunMessageHeader msg_header_;
    std::unordered_map<uint16_t, std::shared_ptr<StunAttribute>> attributes_;
    StunAtrAddress xor_mapped_address_;
    StunAtrAddress mapped_address_;
};



#endif // _STUN_MESSAGE_H
